package com.kronos.gui;

import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.kronos.audio.SoundStream;
import com.kronos.game.KronosGame;

public class ImageFontField extends Drawable {
	static private final char BACKSPACE = 8;
	static private final char PASSWORD_CHAR = 42;

	private Texture image;
	private TextureRegion region;

	private OrthographicCamera camera;
	private float mouseX = 0.0F, mouseY = 0.0F;
	private Vector3 vec;

	// Width and height of button region
	private int imgWidth = 174;
	private int imgHeight = 33;
	private int SCALE = 1;

	private BitmapFont font;

	private String str;
	private int maxLength;

	private int blinkerPos = 0;
	private int visibleTextStart = 0, visibleTextEnd;

	private boolean buttonSelected;
	private ShapeRenderer sr;

	private StringBuilder passwordBuffer;

	private boolean lastSelection = false;

	public ImageFontField(int x, int y, OrthographicCamera camera) {
		this.x = x;
		this.y = y;
		this.str = "";

		this.camera = camera;

		this.vec = new Vector3();

		this.image = KronosGame.manager.getTexture("gui.png");
		this.region = new TextureRegion(this.image, 14, 16, this.imgWidth, this.imgHeight);

		this.buttonSelected = false;

		this.font = new BitmapFont();

		sr = new ShapeRenderer();

		setMaxLength(50);
	}

	private String insert(int position, CharSequence character, String to) {
		if (to.length() == 0) {
			return character.toString();
		}
		return to.substring(0, position) + character;
	}

	public void setMaxLength(int maxlength) {
		this.maxLength = maxlength;
	}

	private boolean withinMaxLength(int size) {
		return maxLength <= 0 || size < maxLength;
	}

	public void setString(String str) {
		this.str = str;
	}

	private boolean isValidCharacter(char character) {
		return ((character >= 48 && character <= 57) || (character >= 65 && character <= 90) || (character >= 97 && character <= 122));
	}

	public void update() {
	}

	private boolean inBounds() {
		float mouseX = this.mouseX;
		float mouseY = this.mouseY;

		vec.set(mouseX, mouseY, 0);
		camera.unproject(vec);
		// (0,0) Starts at bottom left corner
		return ((vec.x >= x && vec.x <= x + region.getRegionWidth() * SCALE) && (vec.y <= y + region.getRegionHeight() * SCALE && vec.y >= y));
	}

	private void updateDisplayText() {
		int textLength = str.length();

		StringBuilder buffer = new StringBuilder();
		for (int i = 0; i < textLength; i++) {
			char c = str.charAt(i);
			buffer.append(font.containsCharacter(c) ? c : ' ');
		}
		String newDisplayText = buffer.toString();

		if (this.passwordField && font.containsCharacter(PASSWORD_CHAR) && !disabled) {
			if (passwordBuffer == null) {
				passwordBuffer = new StringBuilder(str.length());
			}
			if (passwordBuffer.length() > textLength) {
				passwordBuffer.setLength(textLength);
			} else {
				for (int i = passwordBuffer.length(); i < textLength; i++) {
					passwordBuffer.append(PASSWORD_CHAR);
				}
			}
			str = passwordBuffer.toString();
		} else {
			str = newDisplayText;
		}
	}

	@Override
	public boolean keyTyped(char character) {
		boolean backspace = character == BACKSPACE;

		if (buttonSelected && !disabled) {
			if (backspace) {
				if (blinkerPos > 0) {
					if (font.getBounds(str).width >= region.getRegionWidth() * SCALE) {
						visibleTextStart -= 1;
						str = str.substring(0, blinkerPos - 1) + str.substring(blinkerPos--);
					} else {
						str = str.substring(0, blinkerPos - 1) + str.substring(blinkerPos--);
					}
				}
			} else if (this.isValidCharacter(character)) {
				if (!withinMaxLength(str.length())) {
					return true;
				}
				String insertChar = String.valueOf(character);

				str = insert(blinkerPos++, insertChar, str);

				if (font.getBounds(str).width >= region.getRegionWidth() * SCALE) {
					visibleTextStart += 1;
				}
			}
			this.visibleTextEnd = str.length();
		}
		updateDisplayText();
		return false;
	}

	@Override
	public boolean keyDown(int keycode) {
		return false;
	}

	@Override
	public boolean keyUp(int keycode) {
		return false;
	}

	@Override
	public boolean touchDown(int screenX, int screenY, int pointer, int button) {
		if (inBounds() && !lastSelection) {
			SoundStream.playSound(2);
			lastSelection = true;
			Gdx.input.setOnscreenKeyboardVisible(true);
		} else {
			lastSelection = false;
			Gdx.input.setOnscreenKeyboardVisible(false);
		}

		if (inBounds()) {
			buttonSelected = true; 
		} else {
			buttonSelected = false; 
		}
		return false;
	}

	@Override
	public boolean touchUp(int screenX, int screenY, int pointer, int button) {
		return false;
	}

	@Override
	public boolean touchDragged(int screenX, int screenY, int pointer) {
		return false;
	}

	@Override
	public boolean scrolled(int amount) {
		return false;
	}

	@Override
	public boolean mouseMoved(int screenX, int screenY) {
		this.mouseX = screenX;
		this.mouseY = screenY;
		return false;
	}

	public void render(SpriteBatch sb) {
		if (buttonSelected) {
			Gdx.gl.glEnable(GL20.GL_BLEND);
			Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

			sr.setColor(0.0f, 0.0f, 0.0f, 0.1f);
			sr.begin(ShapeType.Line);
			sr.rectLine(this.x + region.getRegionWidth() / 2, this.y, this.x + region.getRegionWidth() / 2, this.y + region.getRegionHeight(), region.getRegionWidth());
			sr.end();

			Gdx.gl.glDisable(GL20.GL_BLEND);
			if(Gdx.app.getType() == ApplicationType.Android && this.inBounds()) {
				Gdx.input.setOnscreenKeyboardVisible(true);
			} else {
				Gdx.input.setOnscreenKeyboardVisible(false);
			}
		}

		sb.begin();
		sb.setColor(1.0f, 1.0f, 1.0f, 0.2f);

		sb.draw(region, x, y, imgWidth * SCALE, imgHeight * SCALE);

		font.draw(sb, this.str, this.x + 3, this.y + this.region.getRegionHeight() / 2 * SCALE + this.font.getBounds(this.str).height / 2, this.visibleTextStart, this.visibleTextEnd);

		sb.end();
	}

	@Override
	public boolean touchDown(float x, float y, int pointer, int button) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean tap(float x, float y, int count, int button) {
		this.mouseX = x;
		this.mouseY = y; 
		return false;
	}

	@Override
	public boolean longPress(float x, float y) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean fling(float velocityX, float velocityY, int button) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean pan(float x, float y, float deltaX, float deltaY) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean panStop(float x, float y, int pointer, int button) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean zoom(float initialDistance, float distance) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2,
			Vector2 pointer1, Vector2 pointer2) {
		// TODO Auto-generated method stub
		return false;
	}
}
